package com.punai.system.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.protobuf.ServiceException;
import com.punai.common.bos.KVCBO;
import com.punai.common.bos.RestResponse;
import com.punai.common.constant.CsPermissionConstants;
import com.punai.common.constant.CsRoleConstants;
import com.punai.common.properties.SystemTypeProperties;
import com.punai.system.bo.GetPermissionVo;
import com.punai.system.bo.cs.EpPermissionBo;
import com.punai.system.domain.CsLinkRolePermission;
import com.punai.system.domain.CsLinkUserRole;
import com.punai.system.domain.CsRole;
import com.punai.system.mapper.CsLinkRolePermissionMapper;
import com.punai.system.mapper.CsLinkUserRoleMapper;
import com.punai.system.mapper.CsRoleMapper;
import com.punai.system.service.ApiRequest;
import com.punai.system.service.CsRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class CsRoleServiceImpl extends ServiceImpl<CsRoleMapper, CsRole> implements CsRoleService {


    @Autowired
    private CsRoleMapper csRoleMapper;
    @Autowired
    private ApiRequest apiRequest;
    @Autowired
    private SystemTypeProperties systemTypeProperties;
    @Autowired
    private CsLinkRolePermissionMapper csLinkRolePermissionMapper;

    @Autowired
    private CsLinkUserRoleMapper csLinkUserRoleMapper;
    @Override
    public List<CsRole> selectRoleList(CsRole role) {
        String name = role.getName();
        Long companyId = role.getCompanyId();
        LambdaQueryWrapper<CsRole> like = Wrappers.<CsRole>lambdaQuery()
                .like(StrUtil.isNotEmpty(name),CsRole::getName, name)
                .eq(CsRole::getCompanyId,companyId);
        return csRoleMapper.selectList(like);
    }

    @Override
    public Boolean checkRoleNameUnique(CsRole role) {
        String name = role.getName();
        Long companyId = role.getCompanyId();
        LambdaQueryWrapper<CsRole> like = Wrappers.<CsRole>lambdaQuery()
                .eq(CsRole::getName, name)
                .eq(CsRole::getCompanyId,companyId);
        return csRoleMapper.selectCount(like) > 0;
    }

    @Override
    @Transactional
    public int insertRole(CsRole role)  {
        List<String> menuIds = role.getMenuIds();
        Long companyId = role.getCompanyId();
        // 保存
        // 校验角色名称是否重复
        int insert = csRoleMapper.insert(role);
        String roleId = role.getId();
        for (String menuId : menuIds) {
            if(menuId.contains(CsRoleConstants.SELECT_CS_ROLE_PERM_SPLITTER)) {
                List<String> split = StrUtil.split(menuId, CsRoleConstants.SELECT_CS_ROLE_PERM_SPLITTER);
                String type = split.get(0);
                String code = split.get(1);
                CsLinkRolePermission rp = new CsLinkRolePermission();
                rp.setCompanyId(companyId);
                rp.setRoleid(roleId);
                rp.setType(type);
                rp.setCode(code);
                csLinkRolePermissionMapper.insert(rp);
            }
        }
        return insert;
    }

    /**
     * 检查重复名称
     * @param name
     * @param companyId
     * @param id
     * @return   true 无重复    false 有重复
     */
    private Boolean checkName(String name,Long companyId,String id) {
        CsRole csRole = csRoleMapper.selectOne(
                Wrappers.<CsRole>lambdaQuery()
                        .eq(CsRole::getName, name)
                        .eq(CsRole::getCompanyId, companyId)
        );
        if (csRole == null) {
            return true;
        }
        return csRole.getId().equals(id);
    }


    @Override
    public EpPermissionBo getEpPermission(CsRole role) {
        String id = role.getId();
        Long companyId = role.getCompanyId();
        String epId = systemTypeProperties.getEpId();
        EpPermissionBo res = new EpPermissionBo();
        if (StrUtil.isEmpty(epId)) {
            return res;
        }
        // 得获取 企业的权限
        RestResponse<Map<String, List<String>>> permission = apiRequest.getPermission(new GetPermissionVo(epId));
        RestResponse<Map<String,Map<String, String>>> allPermission = apiRequest.getAllPermission();
        // 前端对象
        List<KVCBO> roots = new ArrayList<>();
        if (permission.getCode().equals(0)) {
            Map<String,Map<String, String>> allCodeName = allPermission.getData();
            Map<String, List<String>> data = permission.getData();
            if (MapUtil.isNotEmpty(data)) {
                Set<String> keys = data.keySet();
                // 组建前端对象
                for (String key : keys) {
                    String desc = CsPermissionConstants.ConversionType.getDescByName(key);
                    String descKey = CsPermissionConstants.ConversionType.getDescKeyByName(key);
                    List<KVCBO> resList = new ArrayList<>();
                    List<String> codes = data.get(key);
                    Map<String, String> descMap = allCodeName.get(descKey);
                    for (String code : codes) {
                        String name = descMap.get(code);
                        resList.add(new KVCBO(name,key + CsRoleConstants.SELECT_CS_ROLE_PERM_SPLITTER + code));
                    }
                    KVCBO root = new KVCBO();
                    root.setKey(desc);
                    root.setValue(key);
                    root.setChildren(resList);
                    roots.add(root);
                }
            }
        }
        // 获取当前角色配置的权限
        List<String> checkCodes = new ArrayList<>();
        if (StrUtil.isNotEmpty(id)) {
            checkCodes = getLinkCodeByRoleId(id,companyId);
        }

        res.setAllPerm(roots);
        res.setHavePerm(checkCodes);
        return res;
    }

    @Override
    public CsRole getCsRole(String id, Long companyId) {
        return csRoleMapper.selectOne(
                Wrappers.<CsRole>lambdaQuery()
                        .eq(CsRole::getId,id)
                        .eq(CsRole::getCompanyId,companyId)
        );
    }

    @Override
    @Transactional
    public int updateRole(CsRole role) throws ServiceException {
        String id = role.getId();
        String name = role.getName();
        Long companyId = role.getCompanyId();
        List<String> menuIds = role.getMenuIds();
        if (!checkName(name,companyId,id)) {
            throw new ServiceException("修改角色'" + role.getName() + "'失败，角色名称已存在");
        }

        // 删除原来的资源
        csLinkRolePermissionMapper.delete(
                Wrappers.<CsLinkRolePermission>lambdaQuery()
                        .eq(CsLinkRolePermission::getCompanyId, companyId)
                        .eq(CsLinkRolePermission::getRoleid, id)
        );

        // 重新添加
        for (String menuId : menuIds) {
            if(menuId.contains(CsRoleConstants.SELECT_CS_ROLE_PERM_SPLITTER)) {
                List<String> split = StrUtil.split(menuId, CsRoleConstants.SELECT_CS_ROLE_PERM_SPLITTER);
                String type = split.get(0);
                String code = split.get(1);
                CsLinkRolePermission rp = new CsLinkRolePermission();
                rp.setCompanyId(companyId);
                rp.setRoleid(id);
                rp.setType(type);
                rp.setCode(code);
                csLinkRolePermissionMapper.insert(rp);
            }
        }

        LambdaQueryWrapper<CsRole> updateWrapper = Wrappers.<CsRole>lambdaQuery()
                .eq(CsRole::getCompanyId, companyId)
                .eq(CsRole::getId, id);
        return csRoleMapper.update(role, updateWrapper);
    }

    @Override
    @Transactional
    public int deleteRole(Long[] roleIds, Long companyId) {
        // 删除 用户关联的角色
        csLinkUserRoleMapper.delete(
                Wrappers.<CsLinkUserRole>lambdaQuery()
                        .eq(CsLinkUserRole::getCompanyId,companyId)
                        .in(CsLinkUserRole::getRoleid,roleIds)
        );
        // 删除 角色关联的 权限
        csLinkRolePermissionMapper.delete(
                Wrappers.<CsLinkRolePermission>lambdaQuery()
                        .eq(CsLinkRolePermission::getCompanyId,companyId)
                        .in(CsLinkRolePermission::getRoleid,roleIds)
        );
        // 删除角色
        csRoleMapper.delete(
                Wrappers.<CsRole>lambdaQuery()
                        .eq(CsRole::getCompanyId,companyId)
                        .in(CsRole::getId,roleIds)
        );
        return 1;
    }

    private List<String> getLinkCodeByRoleId(String id,Long companyId) {
        List<CsLinkRolePermission> allRP = csLinkRolePermissionMapper.selectList(
                Wrappers.<CsLinkRolePermission>lambdaQuery()
                        .eq(CsLinkRolePermission::getRoleid, id)
                        .eq(CsLinkRolePermission::getCompanyId, companyId)
        );
        List<String> resList = new ArrayList<>();
        Map<String, List<CsLinkRolePermission>> typePermissions = allRP.stream().collect(Collectors.groupingBy(CsLinkRolePermission::getType));
        Set<Map.Entry<String, List<CsLinkRolePermission>>> entries = typePermissions.entrySet();
        for (Map.Entry<String, List<CsLinkRolePermission>> entry : entries) {
            String desc = entry.getKey();
            List<CsLinkRolePermission> value = entry.getValue();
            for (CsLinkRolePermission csLinkRolePermission : value) {
                String code = csLinkRolePermission.getCode();
                resList.add( desc + CsRoleConstants.SELECT_CS_ROLE_PERM_SPLITTER + code);
            }
        }
        return resList;
    }

}
